package com.such.kit.validate.validator;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.such.kit.Logger;
import com.such.kit.placeholder.PlaceholderCommons;
import com.such.kit.string.StringCommons;
import com.such.kit.validate.validator.bean.VerifyResult;
import com.such.kit.validate.validator.exception.CheckParamsException;

/**
 * @author SUCH
 * <pre>
 * 校验器抽象类
 * 通过实现抽象类完成更精细的校验，并按规则构建校验异常信息
 * </pre>
 */
public abstract class Validator {

	protected static final String PARAMS_JSON = "PARAMS_JSON";
	protected static final String PARAMS_JSON_KEY = "#[PARAMS_JSON]";

	/**
	 * <pre>
	 * 检查参数列表与检验器是否匹配
	 * </pre>
	 * @param params 参数集
	 * @return [true 匹配 | false 不匹配]
	 */
	protected abstract boolean checkParams(List<String> params);

	/**
	 * <pre>
	 * 校验实现
	 * </pre>
	 * @param value 待校验值
	 * @param params 参数集
	 * @return [true 校验通过 | false 校验不通过]
	 */
	protected abstract boolean verify(String value, List<String> params);

	/**
	 * <pre>
	 * 获取异常信息模板
	 * 可以在异常信息模板使用 {@link PlaceholderCommons 占位符} 按顺序引用参数集
	 * 
	 * [举例]
	 *   xxx #[1] xxx #[2] xxx，#[1]、#[2] 会被参数列表中下标为 0、1 的参数替换
	 *   xxx #[PARAMS_JSON] xxx，PARAMS_JSON 为内置的 {@link PlaceholderCommons 占位符}，表示引用整个参数集，参数集会被转换为 v1, v2 ... 格式的字符串
	 * </pre>
	 * @param params 参数集
	 * @return 异常信息模板
	 */
	protected abstract String getVerifyMessage(List<String> params);

	/**
	 * <pre>
	 * 执行校验
	 * </pre>
	 * @param value 待校验值
	 * @param params 参数集
	 * @return 校验结果
	 */
	public VerifyResult execute(String value, String... params) {
		if (params == null) {
			params = new String[0];
		}
		return execute(value, Arrays.stream(params).collect(Collectors.toList()));
	}

	/**
	 * <pre>
	 * 执行校验
	 * </pre>
	 * @param value 待校验值
	 * @param params 参数集
	 * @return 校验结果
	 */
	public VerifyResult execute(String value, List<String> params) {
		if (params == null) {
			params = new ArrayList<String>();
		}
		Logger.debug(getClass(), StringCommons.merger("校验器 [", getClass().getName(), "] 待校验值 [", value, "], 参数集 ", params.toString()));

		if (!checkParams(params)) {
			throw new CheckParamsException(getClass().getName(), params);
		}
		if (!verify(value, params)) {
			return new VerifyResult(buildMessage(value, params));
		}

		return new VerifyResult();
	}

	/**
	 * <pre>
	 * 构建异常信息
	 * </pre>
	 * @param value 待校验值
	 * @param params 参数集
	 * @return 异常信息
	 */
	protected String buildMessage(String value, List<String> params) {
		Map<String, String> paramsMap = new HashMap<String, String>();
		for (int i = 0; i < params.size(); i++) {
			String param = params.get(i);
			paramsMap.put(String.valueOf(i + 1), param);
		}
		paramsMap.put(PARAMS_JSON, StringCommons.merger(params.toArray(), ", ", true));
		return PlaceholderCommons.replacePlaceholder(getVerifyMessage(params), paramsMap);
	}

}
